/* 
 * File:   main.c
 * Author: Server
 *
 * Created on 19 November 2010, 18:14
 */
#define BAUD 57600
#define send_m(x) loop_until_bit_is_set(UCSRA, UDRE);UDR=(x);
#define F_BUZZER 2700

#include <stdio.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <util/setbaud.h>
#include <util/delay.h>

/*
 * 
 */
uint8_t EEMEM eep_atas = 255;
uint8_t EEMEM eep_bawah = 255;
uint8_t EEMEM eep_mode = 3;

volatile double suhu;//double
volatile uint8_t batas_atas;
volatile uint8_t batas_bawah;
volatile uint8_t mode;
/*
 * Mode alarm:
 *  1. mode = 0, window comparator, alarm berbunyi jika suhu berada di rentang batas bawah sampai batas atas
 *  2. mode = 1, high, alarm berbunyi jika suhu lebih dari batas atas, batas bawah tidak digunakan
 *  3. mode = 2, low, alarm berbunyi jika suhu lebih rendah dari batas bawah, batas atas tidak digunakan
 *  4. mode = 3, inverted window comparator, alarm berbunyi jika suhu lebih dari batas atas atau kurang dari batas bawah, mode ini adalah default mode
 */


void bip(void);
int send(char,FILE*);


int main(void) {
    DDRB = 0b00000010;
    sei();
    bip();//startup-beat
    _delay_ms(200);
    bip();
    /*INIT EEPROM*/
    eeprom_busy_wait();
    batas_atas = eeprom_read_byte(&eep_atas);
    batas_bawah = eeprom_read_byte(&eep_bawah);
	mode = eeprom_read_byte(&eep_mode);
    /*
    if(batas_atas == 255 || !batas_bawah == 255 ){
        _delay_ms(1000);
        bip();bip();
        _delay_ms(250);
        bip();bip();
        _delay_ms(250);
        bip();bip();
    }
    */

    /*INIT SWITCH*/
    //port D2 dan D3 sebagai input pull-up enable
    PORTD = _BV(PD2) | _BV(PD3);
    //interrupt falling edge di INT0 iNT1
    MCUCR |= (_BV(ISC11) & ~_BV(ISC10)) | (_BV(ISC01) & ~_BV(ISC00));
    //enable interrupt
    GICR |= _BV(INT1) | _BV(INT0);

    /*INIT TIMER1*/
    //precaler 1024 , mode CTC, COM=00
    //TCCR1A = 0;
    TCCR1B = _BV(CS12) | _BV(CS10) | _BV(WGM12);
    //compare di 10800
    OCR1A = 10800;
    //interrupt enable
    TIMSK = _BV(OCIE1A);

    /*INIT UART*/
    //baudrate 57600
    UBRRL = UBRRL_VALUE;
    UBRRH = UBRRH_VALUE;
    //enable transmit & receive , RX interrupt enable
    UCSRB = _BV(TXEN) | _BV(RXEN) | _BV(RXCIE);
    //mode 8/N/1 no flow
    UCSRC = ((_BV(URSEL) & ~(_BV(UMSEL)) & ~(_BV(UPM0)) & ~(_BV(UPM1)) & ~(_BV(USBS)))  | _BV(UCSZ1) | _BV(UCSZ0)) & ~(_BV(UCPOL));
    fdevopen(send,0);
    
    /*INIT ADC*/
    //internal ref, mux pin ADC0
    ADMUX = _BV(REFS1) | _BV(REFS0);
    //adc enable, prescaler 128 , interrupt enabled, free running
    ADCSR = _BV(ADEN) | _BV(ADSC) |_BV(ADFR) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
    /*END INIT*/
    _delay_ms(3000);
    while(1){
        switch(mode){
            case 0:
                if(suhu <= batas_atas && suhu >= batas_bawah){
                    cli();
                    bip();
                    _delay_ms(100);
                    bip();
                    _delay_ms(100);
                    bip();
                    sei();
                }
            case 1:
                if(suhu > batas_atas){
                    cli();
                    bip();
                    _delay_ms(100);
                    bip();
                    _delay_ms(100);
                    bip();
                    sei();
                }
                break;
            case 2:
                if(suhu < batas_bawah){
                    cli();
                    bip();
                    _delay_ms(100);
                    bip();
                    _delay_ms(100);
                    bip();
                    sei();
                }
                break;
            case 3:
                if(suhu < batas_bawah || suhu > batas_atas){
                    cli();
                    bip();
                    _delay_ms(100);
                    bip();
                    _delay_ms(100);
                    bip();
                    sei();
                }
        }
        _delay_ms(1000);
    }
    return 0;
}

int send(char ch, FILE * f){
    if (ch == '\n')
        send('\r',0);
    loop_until_bit_is_set(UCSRA, UDRE);
    UDR = ch;
    return 0;

    //bip();
}
void bip(void){
    unsigned short int x;
    for(x=0;x<60;x++){
        PORTB |= _BV(PB1);
        _delay_us(500000 / F_BUZZER);
        PORTB &= ~_BV(PB1);
        _delay_us(500000 / F_BUZZER);
    }
}
ISR(USART_RXC_vect){
    static unsigned char special;
    char x = UDR;

    if(x == 27){
        special = 1;
    }else if(special && x == 91){
        special++;
    }else if(special == 2){
        special = 0;
        if(x == 65) {
            batas_atas++;
//            goto atas;
        }
        else if(x == 66){
            batas_atas--;
//            goto atas;
        }
        else if(x == 67){
            batas_bawah++;
//            goto bawah;
        }
        else if(x == 68){
            batas_bawah--;
//            goto bawah;
        }

//    }else if(x == 'a'){
//        atas:
//        printf("batas atas:%u\370C\n",batas_atas);
//    }else if(x == 'b'){
//        bawah:
//        printf("batas bawah:%u\370C\n",batas_bawah);
      }
//    printf("%d %x\n",x,x);
}
ISR(ADC_vect){
    unsigned int suhu_adc;
    suhu_adc = ADC;
    //suhu_adc = ADCL;
    //suhu_adc += ADCH << 8;
    suhu = ((long)suhu_adc * 269.1) / 1024.00;
}

ISR(INT0_vect){
    //S1
    _delay_ms(1);
    if(!(PIND & _BV(PIND2)))bip();
    //sei();
}
ISR(INT1_vect){
    //S2
    uint8_t x = 0;
    uint8_t y;
    for(y = 0;y < 7;y++){
        _delay_ms(10);
        x += (PIND & _BV(PIND3));
    }
    if(!x){
        mode++;
        mode &= 3;
        for(x = mode;x  < 255;x--){
            bip();
            _delay_ms(300);
        }
        //_delay_ms(1000);
    }

}

ISR(TIMER1_COMPA_vect){
    static uint8_t x;
    if (!x){
        eeprom_update_byte(&eep_atas,batas_atas);
        eeprom_update_byte(&eep_bawah,batas_bawah);
		eeprom_update_byte(&eep_mode,mode);
        x=5;
    }else{
        x--;
    }
    //send_m(0x1b);send_m(0x5b);send_m(';');send_m('H');
    //send_m(0x1b);send_m(0x5b);send_m('K');
    //send(0x1b,0);send(0x5b,0);send('2',0);send('J',0);//clear display
    //send_m(12);
    printf("\014%.3f\370C\nBatas atas:%d\370C\nBatas bawah:%d\370C\nMode:%u",suhu,batas_atas,batas_bawah,mode+1);
    //derajat \370 atau \247
}
